package nu.boomboom.smartfsync.impl;

import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import nu.boomboom.smartfsync.IDifferences;
import nu.boomboom.smartfsync.IDifferentElements;
import nu.boomboom.smartfsync.IDir;
import nu.boomboom.smartfsync.IElement;

public class DifferencesImpl implements IDifferences {
	private final Set<IElement> addedElements;
	private final Set<IElement> deletedElements;
	private final DirImpl baseDir;
	private final Set<IDifferentElements> differentElements;
	private final DirImpl comparisonTargetDir;

	DifferencesImpl(DirImpl baseDir, DirImpl comparisonTargetDir,
			Set<IDifferentElements> differentElements,
			Set<IElement> addedElements, Set<IElement> deletedElement) {
		this.addedElements = addedElements;
		this.deletedElements = deletedElement;
		this.baseDir = baseDir;
		this.comparisonTargetDir = comparisonTargetDir;
		this.differentElements = differentElements;
	}

	@Override
	public Set<IElement> addedElements() {
		return addedElements;
	}

	@Override
	public IDir baseDir() {
		return baseDir;
	}

	@Override
	public IDir comparisonTargetDir() {
		return comparisonTargetDir;
	}

	@Override
	public Set<IElement> deletedElements() {
		return deletedElements;
	}

	@Override
	public Set<IDifferentElements> differentElements() {
		return differentElements;
	}

	@Override
	public Set<IDifferences> subDirDiffs() {
		// TODO Auto-generated method stub
		return null;
	}

	public static IDifferences createDifferences(DirImpl baseDir,
			DirImpl comparisonTargetDir) {
		File rawBaseDirFile = baseDir.dir(), rawComparisonTargetDirFile = comparisonTargetDir
				.dir();

		Set<String> filesInBaseDir = new HashSet<String>(Arrays
				.asList(rawBaseDirFile.list()));
		Set<String> filesInComparisonTargetDir = new HashSet<String>(Arrays
				.asList(rawComparisonTargetDirFile.list()));

		Set<String> uniqueElementsInComparisonTargetDir = new HashSet<String>(
				filesInComparisonTargetDir);
		uniqueElementsInComparisonTargetDir.removeAll(filesInBaseDir);
		Set<IElement> deletedElements = convertFileNameSetToElementSet(
				uniqueElementsInComparisonTargetDir, comparisonTargetDir);

		Set<String> uniqueElementsInBaseDir = new HashSet<String>(
				filesInBaseDir);
		uniqueElementsInBaseDir.removeAll(filesInComparisonTargetDir);
		Set<IElement> addedElements = convertFileNameSetToElementSet(
				uniqueElementsInBaseDir, baseDir);

		Set<String> intersect = new HashSet<String>(filesInBaseDir);
		intersect.removeAll(filesInComparisonTargetDir);
		Set<IDifferentElements> differentElementSet = new HashSet<IDifferentElements>();
		for (String fileName : intersect) {
			File fileInBaseDir = new File(baseDir.dir(), fileName);
			File fileInComparisonTargetDir = new File(baseDir.dir(), fileName);
			DifferentElementsImpl differentElements = new DifferentElementsImpl(
					FileSystem.toElement(fileInBaseDir), FileSystem
							.toElement(fileInComparisonTargetDir));
			differentElementSet.add(differentElements);
		}

		return new DifferencesImpl(baseDir, comparisonTargetDir,
				differentElementSet, addedElements, deletedElements);
	}

	static Set<IElement> convertFileNameSetToElementSet(Set<String> fileNames,
			DirImpl baseDir) {
		Set<IElement> elementSet = new HashSet<IElement>();
		for (String fileName : fileNames) {
			File file = new File(baseDir.dir(), fileName);
			IElement element = FileSystem.toElement(file);
			elementSet.add(element);
		}
		return elementSet;
	}

	static class DifferentElementsImpl implements IDifferentElements {
		private final IElement fileInBaseDir;
		private final IElement fileInComparisonTargetDir;

		DifferentElementsImpl(IElement fileInBaseDir,
				IElement fileInComparisonTargetDir) {
			this.fileInBaseDir = fileInBaseDir;
			this.fileInComparisonTargetDir = fileInComparisonTargetDir;
		}

		@Override
		public IElement fileInBaseDir() {
			return fileInBaseDir;
		}

		@Override
		public IElement fileInComparisonTargetDir() {
			return fileInComparisonTargetDir;
		}

	}
}
